package com.piece.core.web.authority;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.web.properties.SecurityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.annotation.security.PermitAll;
import java.util.*;

/**
 * Token处理工厂
 */
@Slf4j
public class AuthorityFactory {

    private Map<String, AuthorityService> serviceMap;
    private String defaultType;

    public AuthorityFactory(Map<String, AuthorityService> authorityServiceMap) {
        log.info("加载 AuthorityFactory ...");
        this.serviceMap = authorityServiceMap;
        this.init();
    }

    public void init() {
        Iterator<Map.Entry<String, AuthorityService>> it = this.serviceMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, AuthorityService> entry = it.next();
            if (null == this.defaultType) {
                this.defaultType = entry.getKey();
            }
        }
    }

    public static final String[] ENDPOINTS = {
            "/favicon.ico",
            "/*.html",
            "/**/*.html",
            "/*.css",
            "/**/*.css",
            "/*.js",
            "/**/*.js",
            "/image/**",
            "/images/**",
            "/*.zz",
            "/lib/**",
            "/fonts/**",
            "/v2/**",
            "/*/v2/api-docs",
            "/doc.html",
            "/swagger/api-docs",
            "/swagger-ui.html",
            "/swagger-ui/index.html",
            "/swagger-resources/**",
            "/static/**",
            "/webjars/**",
            "/druid/**",
            "/site/**",
            "/oauth/**",
            "/actuator/**"
    };

    /**
     * 获取所有无需验证的请求
     */
    public Multimap<HttpMethod, String> permitAllMethods(ApplicationContext applicationContext, SecurityProperties properties) {
        Multimap<HttpMethod, String> result = HashMultimap.create();
        // 获得接口对应的 HandlerMethod 集合
        RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)
                applicationContext.getBean("requestMappingHandlerMapping");
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
        // 获得有 @PermitAll @AclPermission 注解的接口
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethodMap.entrySet()) {
            HandlerMethod handlerMethod = entry.getValue();
            if (!handlerMethod.hasMethodAnnotation(PermitAll.class) && !handlerMethod.hasMethodAnnotation(AclPermission.class)) {
                continue;
            }

            if (handlerMethod.hasMethodAnnotation(AclPermission.class)) {
                AclPermission aclPermission = handlerMethod.getMethodAnnotation(AclPermission.class);
                if (aclPermission.checkLogin()) {
                    continue;
                }
            }

            if (entry.getKey().getPatternsCondition() == null) {
                continue;
            }
            Set<String> urls = entry.getKey().getPatternsCondition().getPatterns();
            entry.getKey().getMethodsCondition().getMethods().forEach(requestMethod -> {
                switch (requestMethod) {
                    case GET:
                        result.putAll(HttpMethod.GET, urls);
                        break;
                    case POST:
                        result.putAll(HttpMethod.POST, urls);
                        break;
                    case PUT:
                        result.putAll(HttpMethod.PUT, urls);
                        break;
                    case DELETE:
                        result.putAll(HttpMethod.DELETE, urls);
                        break;
                }
            });
        }

        // 静态资源文件
        for (String source: ENDPOINTS) {
            result.put(HttpMethod.GET, source);
        }

        // 获得自定义取消验证接口
        String[] ignoreUrls = properties.getIgnoreUrl();
        for (String url : ignoreUrls) {
            result.putAll(HttpMethod.GET, Collections.singleton(url));
            result.putAll(HttpMethod.POST, Collections.singleton(url));
            result.putAll(HttpMethod.PUT, Collections.singleton(url));
            result.putAll(HttpMethod.DELETE, Collections.singleton(url));
        }

        return result;
    }

    /**
     * 获取所有静态资源文件
     */
    public Multimap<HttpMethod, String> permitAllSource() {
        Multimap<HttpMethod, String> result = HashMultimap.create();
        for (String source: ENDPOINTS) {
            result.put(HttpMethod.GET, source);
        }
        return result;
    }

    public AuthorityService get() {
        return serviceMap.get(defaultType);
    }

    public AuthorityService get(String type) {
        return serviceMap.get(type);
    }
}
